﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace BneyBaruch.Ingest.Core.ServiceModel
{
    /// <summary>
    /// Generic service proxy wrapper.
    /// Clean up and close channel after using.
    /// </summary>
    /// <example>
    /// string response = null;
    /// DuplexServiceProxy&lt;IUnitTestService&gt;.Call(p =>
    /// {
    ///     response = p.DoStuff();
    /// }
    /// </example>
    /// <example>
    /// string response = null;
    /// using(DuplexServiceProxy&lt;IUnitTestService&gt; service = new DuplexServiceProxy&lt;IUnitTestService&gt;())
    /// {
    ///     response = service.Proxy.DoStuff();
    /// }
    /// </example>
    /// <typeparam name="TInterface">The type of the service interface - service contract.</typeparam>
    public class DuplexServiceProxy<TInterface> : DuplexClientBase<TInterface>, IDisposable where TInterface : class
    {
        #region Delegates

        public delegate void CallDuplexServiceDelegate<TInterface>(TInterface proxy);

        #endregion

        #region Constructors

        public DuplexServiceProxy(InstanceContext instanceContext)
            : base(instanceContext,typeof(TInterface).ToString())
        {
        }

        public DuplexServiceProxy(InstanceContext instanceContext,string endpointConfigurationName)
            : base(instanceContext,endpointConfigurationName)
        {
        }

        #endregion

        #region Proxy Property

        public TInterface Proxy
        {
            get
            {
                return this.Channel;
            }
        }

        #endregion

        #region Static Call Methods

        public static void Call(CallDuplexServiceDelegate<TInterface> proxyDelegate,InstanceContext instanceContext)
        {
            Call(proxyDelegate,instanceContext, typeof(TInterface).ToString());
        }

        public static void Call(CallDuplexServiceDelegate<TInterface> proxyDelegate,InstanceContext instanceContext, string endpointConfigurationName)
        {
            DuplexChannelFactory<TInterface> channel = new DuplexChannelFactory<TInterface>(instanceContext,endpointConfigurationName);
            try
            {
                proxyDelegate(channel.CreateChannel());
            }

            finally
            {
                if (channel.State == CommunicationState.Faulted)
                {
                    channel.Abort();
                }
                else
                {
                    try
                    {
                        channel.Close();
                    }
                    catch
                    {
                        channel.Abort();
                    }
                }
            }
        }

        #endregion

        #region IDisposable Implementations

        public void Dispose()
        {
            if (this.State == CommunicationState.Faulted)
            {
                base.Abort();
            }
            else
            {
                try
                {
                    base.Close();
                }
                catch
                {
                    base.Abort();
                }
            }
        }

        #endregion
    }
}
